﻿// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
//
// 本项目主要遵循 MIT 许可证和 Apache 许可证（版本 2.0）进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动！任何基于本项目二次开发而产生的一切法律纠纷和责任，我们不承担任何责任！

using Furion.FriendlyException;
using Mapster;
using SqlSugar;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using Admin.NET.Application.Entity;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Admin.NET.Core.Service;
namespace Admin.NET.Application;

/// <summary>
/// 审批流程记录服务 🧩
/// </summary>
[ApiDescriptionSettings(ApplicationConst.GroupNameStore, Order = 100)]
public partial class StoreProcessRecordService : IDynamicApiController, ITransient
{
    private readonly SqlSugarRepository<StoreProcessRecord> _storeProcessRecordRep;
    private readonly StoreMaterialsService _storeMaterialsService;
    private readonly ISqlSugarClient _sqlSugarClient;
    private readonly SysOrgService _sysOrgService;

    public StoreProcessRecordService(SqlSugarRepository<StoreProcessRecord> storeProcessRecordRep, StoreMaterialsService storeMaterialsService, ISqlSugarClient sqlSugarClient, SysOrgService sysOrgService)
    {
        _storeProcessRecordRep = storeProcessRecordRep;
        _storeMaterialsService = storeMaterialsService;
        _sqlSugarClient = sqlSugarClient;
        _sysOrgService = sysOrgService;
    }

    /// <summary>
    /// 分页查询审批流程记录 🔖
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [DisplayName("分页查询审批流程记录")]
    [ApiDescriptionSettings(Name = "Page"), HttpPost]
    public async Task<SqlSugarPagedList<StoreProcessRecordOutput>> Page(PageStoreProcessRecordInput input)
    {
        input.Keyword = input.Keyword?.Trim();
        var query = _storeProcessRecordRep.AsQueryable()
            .WhereIF(!string.IsNullOrWhiteSpace(input.Keyword), u => u.FlowType.Contains(input.Keyword) || u.BatchNo.Contains(input.Keyword) || u.RequestNo.Contains(input.Keyword) || u.StoreTypeName.Contains(input.Keyword) || u.MaterialName.Contains(input.Keyword) || u.Unit.Contains(input.Keyword) || u.ApplicantName.Contains(input.Keyword) || u.ApplicantDept.Contains(input.Keyword) || u.ReceiverName.Contains(input.Keyword) || u.ReceiverDept.Contains(input.Keyword) || u.Remark.Contains(input.Keyword) || u.ConfirmerName.Contains(input.Keyword))
            .WhereIF(!string.IsNullOrWhiteSpace(input.FlowType), u => u.FlowType.Contains(input.FlowType.Trim()))
            .WhereIF(!string.IsNullOrWhiteSpace(input.BatchNo), u => u.BatchNo.Contains(input.BatchNo.Trim()))
            .WhereIF(!string.IsNullOrWhiteSpace(input.RequestNo), u => u.RequestNo.Contains(input.RequestNo.Trim()))
            .WhereIF(!string.IsNullOrWhiteSpace(input.StoreTypeName), u => u.StoreTypeName.Contains(input.StoreTypeName.Trim()))
            .WhereIF(!string.IsNullOrWhiteSpace(input.MaterialName), u => u.MaterialName.Contains(input.MaterialName.Trim()))
            .WhereIF(!string.IsNullOrWhiteSpace(input.Unit), u => u.Unit.Contains(input.Unit.Trim()))
            .WhereIF(!string.IsNullOrWhiteSpace(input.ApplicantName), u => u.ApplicantName.Contains(input.ApplicantName.Trim()))
            .WhereIF(!string.IsNullOrWhiteSpace(input.ApplicantDept), u => u.ApplicantDept.Contains(input.ApplicantDept.Trim()))
            .WhereIF(!string.IsNullOrWhiteSpace(input.ReceiverName), u => u.ReceiverName.Contains(input.ReceiverName.Trim()))
            .WhereIF(!string.IsNullOrWhiteSpace(input.ReceiverDept), u => u.ReceiverDept.Contains(input.ReceiverDept.Trim()))
            .WhereIF(!string.IsNullOrWhiteSpace(input.Remark), u => u.Remark.Contains(input.Remark.Trim()))
            .WhereIF(!string.IsNullOrWhiteSpace(input.ConfirmerName), u => u.ConfirmerName.Contains(input.ConfirmerName.Trim()))
            .WhereIF(input.StoreTypeId != null, u => u.StoreTypeId == input.StoreTypeId)
            .WhereIF(input.MaterialId != null, u => u.MaterialId == input.MaterialId)
            .WhereIF(input.ApplicantId != null, u => u.ApplicantId == input.ApplicantId)
            .WhereIF(input.ReceiverId != null, u => u.ReceiverId == input.ReceiverId)
            .WhereIF(input.RequestTimeRange?.Length == 2, u => u.RequestTime >= input.RequestTimeRange[0] && u.RequestTime <= input.RequestTimeRange[1])
            .WhereIF(input.ExpectedDateRange?.Length == 2, u => u.ExpectedDate >= input.ExpectedDateRange[0] && u.ExpectedDate <= input.ExpectedDateRange[1])
            .WhereIF(input.CompletedTimeRange?.Length == 2, u => u.CompletedTime >= input.CompletedTimeRange[0] && u.CompletedTime <= input.CompletedTimeRange[1])
            .WhereIF(input.StatusNewOrChange.HasValue, u => u.StatusNewOrChange == input.StatusNewOrChange)
            .WhereIF(input.ApprovalAction.HasValue, u => u.ApprovalAction == input.ApprovalAction)
            .WhereIF(input.ConfirmerId != null, u => u.ConfirmerId == input.ConfirmerId)
            .Select<StoreProcessRecordOutput>();
        var pagedResult = await query.OrderBuilder(input).ToPagedListAsync(input.Page, input.PageSize);

        // 异步构建每个物资的分类完整路径和用户区域完整路径
        foreach (var item in pagedResult.Items)
        {
            if (item.StoreTypeId.HasValue)
            {
                item.StoreTypeDisplayName = await _storeMaterialsService.BuildCategoryPathAsync(item.StoreTypeId.Value);
            }
            
            // 构建申请人区域完整路径
            if (item.ApplicantId > 0)
            {
                var applicantUser = await _sqlSugarClient.Queryable<SysUser>()
                    .Where(u => u.Id == item.ApplicantId)
                    .Select(u => u.OrgId)
                    .FirstAsync();
                if (applicantUser > 0)
                {
                    item.ApplicantDept = await _sysOrgService.BuildOrgPathAsync(applicantUser);
                }
            }
            
            // 构建接收人区域完整路径
            if (item.ReceiverId.HasValue && item.ReceiverId > 0)
            {
                var receiverUser = await _sqlSugarClient.Queryable<SysUser>()
                    .Where(u => u.Id == item.ReceiverId.Value)
                    .Select(u => u.OrgId)
                    .FirstAsync();
                if (receiverUser > 0)
                {
                    item.ReceiverDept = await _sysOrgService.BuildOrgPathAsync(receiverUser);
                }
            }
        }
        
        return pagedResult;
    }

    /// <summary>
    /// 按申请单分页查询审批流程记录汇总 🔖
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [DisplayName("按申请单分页查询审批流程记录汇总")]
    [ApiDescriptionSettings(Name = "PageSummary"), HttpPost]
    public async Task<SqlSugarPagedList<StoreProcessRecordSummaryOutput>> PageSummary(PageStoreProcessRecordInput input)
    {
        input.Keyword = input.Keyword?.Trim();
        
        // 子查询：获取每个申请单的最终状态（按时间排序的最后一条记录）
        var latestRecordQuery = _storeProcessRecordRep.AsQueryable()
            .WhereIF(!string.IsNullOrWhiteSpace(input.Keyword), u => u.FlowType.Contains(input.Keyword) || u.BatchNo.Contains(input.Keyword) || u.RequestNo.Contains(input.Keyword) || u.StoreTypeName.Contains(input.Keyword) || u.MaterialName.Contains(input.Keyword) || u.Unit.Contains(input.Keyword) || u.ApplicantName.Contains(input.Keyword) || u.ApplicantDept.Contains(input.Keyword) || u.ReceiverName.Contains(input.Keyword) || u.ReceiverDept.Contains(input.Keyword) || u.Remark.Contains(input.Keyword) || u.ConfirmerName.Contains(input.Keyword))
            .WhereIF(!string.IsNullOrWhiteSpace(input.FlowType), u => u.FlowType.Contains(input.FlowType.Trim()))
            .WhereIF(!string.IsNullOrWhiteSpace(input.BatchNo), u => u.BatchNo.Contains(input.BatchNo.Trim()))
            .WhereIF(!string.IsNullOrWhiteSpace(input.RequestNo), u => u.RequestNo.Contains(input.RequestNo.Trim()))
            .WhereIF(!string.IsNullOrWhiteSpace(input.StoreTypeName), u => u.StoreTypeName.Contains(input.StoreTypeName.Trim()))
            .WhereIF(!string.IsNullOrWhiteSpace(input.MaterialName), u => u.MaterialName.Contains(input.MaterialName.Trim()))
            .WhereIF(!string.IsNullOrWhiteSpace(input.Unit), u => u.Unit.Contains(input.Unit.Trim()))
            .WhereIF(!string.IsNullOrWhiteSpace(input.ApplicantName), u => u.ApplicantName.Contains(input.ApplicantName.Trim()))
            .WhereIF(!string.IsNullOrWhiteSpace(input.ApplicantDept), u => u.ApplicantDept.Contains(input.ApplicantDept.Trim()))
            .WhereIF(!string.IsNullOrWhiteSpace(input.ReceiverName), u => u.ReceiverName.Contains(input.ReceiverName.Trim()))
            .WhereIF(!string.IsNullOrWhiteSpace(input.ReceiverDept), u => u.ReceiverDept.Contains(input.ReceiverDept.Trim()))
            .WhereIF(!string.IsNullOrWhiteSpace(input.Remark), u => u.Remark.Contains(input.Remark.Trim()))
            .WhereIF(!string.IsNullOrWhiteSpace(input.ConfirmerName), u => u.ConfirmerName.Contains(input.ConfirmerName.Trim()))
            .WhereIF(input.StoreTypeId != null, u => u.StoreTypeId == input.StoreTypeId)
            .WhereIF(input.MaterialId != null, u => u.MaterialId == input.MaterialId)
            .WhereIF(input.ApplicantId != null, u => u.ApplicantId == input.ApplicantId)
            .WhereIF(input.ReceiverId != null, u => u.ReceiverId == input.ReceiverId)
            .WhereIF(input.RequestTimeRange?.Length == 2, u => u.RequestTime >= input.RequestTimeRange[0] && u.RequestTime <= input.RequestTimeRange[1])
            .WhereIF(input.ExpectedDateRange?.Length == 2, u => u.ExpectedDate >= input.ExpectedDateRange[0] && u.ExpectedDate <= input.ExpectedDateRange[1])
            .WhereIF(input.CompletedTimeRange?.Length == 2, u => u.CompletedTime >= input.CompletedTimeRange[0] && u.CompletedTime <= input.CompletedTimeRange[1])
            .WhereIF(input.StatusNewOrChange.HasValue, u => u.StatusNewOrChange == input.StatusNewOrChange)
            .WhereIF(input.ApprovalAction.HasValue, u => u.ApprovalAction == input.ApprovalAction)
            .WhereIF(input.ConfirmerId != null, u => u.ConfirmerId == input.ConfirmerId);

        // 先获取所有数据，然后在内存中分组处理（适用于中等数据量）
        var allRecords = await latestRecordQuery.ToListAsync();
        
        // 按申请单+物资分组，获取每组的最新记录和完整流程
        var latestRecords = allRecords
            .GroupBy(u => new { u.RequestNo, u.MaterialId })
            .Select(g => {
                var latestRecord = g.OrderByDescending(x => x.CreateTime).First();
                var originalRecord = g.OrderBy(x => x.CreateTime).First(); // 最早的记录（原始申请）
                var processSteps = g.OrderBy(x => x.CreateTime)
                    .Select(x => new ProcessStepInfo
                    { 
                        Status = x.ApprovalAction, 
                        Time = x.CreateTime,
                        Confirmer = x.ConfirmerName 
                    })
                    .ToList();
                
                // 判断数量是否发生变化
                var quantityChanged = originalRecord.Quantity != latestRecord.Quantity;
                
                return new StoreProcessRecordSummaryOutput
                {
                    FlowType = latestRecord.FlowType,
                    RequestNo = latestRecord.RequestNo,
                    StoreTypeId = latestRecord.StoreTypeId,
                    StoreTypeName = latestRecord.StoreTypeName,
                    MaterialName = latestRecord.MaterialName,
                    Quantity = latestRecord.Quantity, // 最终数量
                    OriginalQuantity = originalRecord.Quantity, // 原始数量
                    QuantityChanged = quantityChanged, // 数量是否发生变化
                    Unit = latestRecord.Unit,
                    MaterialPrice = latestRecord.MaterialPrice,
                    MaterialPriceTotal = latestRecord.MaterialPriceTotal,
                    ApplicantName = latestRecord.ApplicantName,
                    ApplicantDept = latestRecord.ApplicantDept,
                    ReceiverName = latestRecord.ReceiverName,
                    ReceiverDept = latestRecord.ReceiverDept,
                    RequestTime = latestRecord.RequestTime,
                    ExpectedDate = latestRecord.ExpectedDate,
                    ApprovalAction = latestRecord.ApprovalAction,
                    CompletedTime = latestRecord.CompletedTime,
                    ConfirmerName = latestRecord.ConfirmerName,
                    CreateTime = latestRecord.CreateTime,
                    // 新增：审批流程步骤
                    ProcessSteps = processSteps
                };
            })
            .AsQueryable();

        // 应用排序 - 默认按创建时间降序
        var orderedQuery = input.Order?.ToLower() == "ascending" 
            ? latestRecords.OrderBy(x => x.CreateTime)
            : latestRecords.OrderByDescending(x => x.CreateTime);
        
        // 手动分页
        var totalCount = latestRecords.Count();
        var pageSize = input.PageSize > 0 ? input.PageSize : 20;
        var page = input.Page > 0 ? input.Page : 1;
        var pagedItems = orderedQuery.Skip((page - 1) * pageSize).Take(pageSize).ToList();

        var pagedResult = new SqlSugarPagedList<StoreProcessRecordSummaryOutput>
        {
            Page = page,
            PageSize = pageSize,
            Total = totalCount,
            Items = pagedItems
        };

        // 异步构建每个物资的分类完整路径和用户区域完整路径
        foreach (var item in pagedResult.Items)
        {
            if (item.StoreTypeId.HasValue)
            {
                item.StoreTypeDisplayName = await _storeMaterialsService.BuildCategoryPathAsync(item.StoreTypeId.Value);
            }
        }
        
        // 需要获取原始记录的ApplicantId和ReceiverId来构建组织路径
        var requestNumbers = pagedResult.Items.Select(x => x.RequestNo).ToList();
        var allRequestRecords = await _storeProcessRecordRep.AsQueryable()
            .Where(x => requestNumbers.Contains(x.RequestNo))
            .OrderBy(x => x.CreateTime)
            .ToListAsync();
            
        // 在内存中按申请单分组，获取每组的第一条记录（最早的记录）
        var originalRecords = allRequestRecords
            .GroupBy(x => x.RequestNo)
            .Select(g => g.First())
            .ToList();
            
        // 构建用户区域完整路径
        foreach (var item in pagedResult.Items)
        {
            var originalRecord = originalRecords.FirstOrDefault(x => x.RequestNo == item.RequestNo);
            if (originalRecord != null)
            {
                // 构建申请人区域完整路径
                if (originalRecord.ApplicantId > 0)
                {
                    var applicantUser = await _sqlSugarClient.Queryable<SysUser>()
                        .Where(u => u.Id == originalRecord.ApplicantId)
                        .Select(u => u.OrgId)
                        .FirstAsync();
                    if (applicantUser > 0)
                    {
                        item.ApplicantDept = await _sysOrgService.BuildOrgPathAsync(applicantUser);
                    }
                }
                
                // 构建接收人区域完整路径
                if (originalRecord.ReceiverId.HasValue && originalRecord.ReceiverId > 0)
                {
                    var receiverUser = await _sqlSugarClient.Queryable<SysUser>()
                        .Where(u => u.Id == originalRecord.ReceiverId.Value)
                        .Select(u => u.OrgId)
                        .FirstAsync();
                    if (receiverUser > 0)
                    {
                        item.ReceiverDept = await _sysOrgService.BuildOrgPathAsync(receiverUser);
                    }
                }
            }
        }
        
        return pagedResult;
    }

    /// <summary>
    /// 获取审批流程记录详情 ℹ️
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [DisplayName("获取审批流程记录详情")]
    [ApiDescriptionSettings(Name = "Detail"), HttpGet]
    public async Task<StoreProcessRecord> Detail([FromQuery] QueryByIdStoreProcessRecordInput input)
    {
        return await _storeProcessRecordRep.GetFirstAsync(u => u.Id == input.Id);
    }

    /// <summary>
    /// 增加审批流程记录 ➕
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [DisplayName("增加审批流程记录")]
    [ApiDescriptionSettings(Name = "Add"), HttpPost]
    public async Task<long> Add(AddStoreProcessRecordInput input)
    {
        var entity = input.Adapt<StoreProcessRecord>();
        
        // 如果提供了确认人ID，自动查询并填充确认人姓名
        if (entity.ConfirmerId.HasValue && entity.ConfirmerId.Value > 0)
        {
            var confirmer = await _sqlSugarClient.Queryable<SysUser>()
                .ClearFilter() // 清除所有过滤器（如租户过滤、软删除过滤等）
                .Where(u => u.Id == entity.ConfirmerId.Value)
                .FirstAsync();
                
            if (confirmer != null)
            {
                entity.ConfirmerName = confirmer.RealName;
            }
        }
        
        return await _storeProcessRecordRep.InsertAsync(entity) ? entity.Id : 0;
    }

    /// <summary>
    /// 更新审批流程记录 ✏️
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [DisplayName("更新审批流程记录")]
    [ApiDescriptionSettings(Name = "Update"), HttpPost]
    public async Task Update(UpdateStoreProcessRecordInput input)
    {
        var entity = input.Adapt<StoreProcessRecord>();
        await _storeProcessRecordRep.AsUpdateable(entity)
        .ExecuteCommandAsync();
    }

    /// <summary>
    /// 删除审批流程记录 ❌
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [DisplayName("删除审批流程记录")]
    [ApiDescriptionSettings(Name = "Delete"), HttpPost]
    public async Task Delete(DeleteStoreProcessRecordInput input)
    {
        var entity = await _storeProcessRecordRep.GetFirstAsync(u => u.Id == input.Id) ?? throw Oops.Oh(ErrorCodeEnum.D1002);
        await _storeProcessRecordRep.FakeDeleteAsync(entity);   //假删除
        //await _storeProcessRecordRep.DeleteAsync(entity);   //真删除
    }

    /// <summary>
    /// 批量删除审批流程记录 ❌
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [DisplayName("批量删除审批流程记录")]
    [ApiDescriptionSettings(Name = "BatchDelete"), HttpPost]
    public async Task<int> BatchDelete([Required(ErrorMessage = "主键列表不能为空")]List<DeleteStoreProcessRecordInput> input)
    {
        var exp = Expressionable.Create<StoreProcessRecord>();
        foreach (var row in input) exp = exp.Or(it => it.Id == row.Id);
        var list = await _storeProcessRecordRep.AsQueryable().Where(exp.ToExpression()).ToListAsync();
   
        return await _storeProcessRecordRep.FakeDeleteAsync(list);   //假删除
        //return await _storeProcessRecordRep.DeleteAsync(list);   //真删除
    }
    
    /// <summary>
    /// 导出审批流程记录 🔖
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [DisplayName("导出审批流程记录")]
    [ApiDescriptionSettings(Name = "Export"), HttpPost, NonUnify]
    public async Task<IActionResult> Export(PageStoreProcessRecordInput input)
    {
        var list = (await Page(input)).Items?.Adapt<List<ExportStoreProcessRecordOutput>>() ?? new();
        if (input.SelectKeyList?.Count > 0) list = list.Where(x => input.SelectKeyList.Contains(x.Id)).ToList();
        return ExcelHelper.ExportTemplate(list, "审批流程记录导出");
    }

}
